<?php

namespace tmcore\services\addons\module;

use think\db\exception\DbException;
use think\Exception;
use think\facade\Db;
use tmcore\exceptions\AddonsException;
use tmcore\services\addons\BaseService;
use tmcore\services\addons\ModelService;
use tmcore\services\addons\UtilService;
use tmcore\utils\File;

class Uninstall extends BaseService
{
    protected string $addon_key;

    public function __construct(string $addon = '')
    {
        parent::__construct();
        $this->addon_key = $addon;
    }

    /**
     * 卸载前检验
     * @return true
     * @throws Exception
     */
    protected function check()
    {
        if (!is_dir($this->sys_path . 'admin' . DIRECTORY_SEPARATOR)) throw new Exception('后台 admin 目录不存在');
        if (!is_dir($this->sys_path . 'uniapp' . DIRECTORY_SEPARATOR)) throw new Exception('手机端 uniapp 目录不存在');
        if (!is_dir($this->sys_path . 'pc' . DIRECTORY_SEPARATOR)) throw new Exception('电脑端 pc 目录不存在');

        // 数据检验
        $addon_row = (new ModelService)->getInfoByKey($this->addon_key);
        if(!$addon_row){
            throw new Exception('插件未安装');
        }

        // 检验目录
        $addons_admin_dir = $this->sys_path . 'admin/src/addons/' . $this->addon_key . DIRECTORY_SEPARATOR;
        $addons_app_dir = $this->sys_path . 'uniapp/src/addons/' . $this->addon_key . DIRECTORY_SEPARATOR;
        $addons_pc_dir = $this->sys_path . 'pc/addons/' . $this->addon_key . DIRECTORY_SEPARATOR;
        $addons_server_dir = $this->addon_path . $this->addon_key . DIRECTORY_SEPARATOR;
        $addons_resource_dir = $this->root_path . 'public/addons' . $this->addon_key . DIRECTORY_SEPARATOR;

        $dir_arr = [$addons_admin_dir, $addons_app_dir, $addons_pc_dir, $addons_server_dir, $addons_resource_dir];

        foreach ($dir_arr as $dir) {
            if(is_dir($dir)){
                if(!File::is_write($dir)) throw new Exception( str_replace($this->sys_path, '', $dir) . ' 目录不可写');
            }
        }

        return true;
    }

    /**
     * 卸载插件目录
     * @return true
     */
    protected function uninstallDir()
    {
        $addon_admin_dir = $this->sys_path . 'admin/src/addons/' . $this->addon_key . DIRECTORY_SEPARATOR;
        $addon_app_dir = $this->sys_path . 'uniapp/src/addons/' . $this->addon_key . DIRECTORY_SEPARATOR;
        $addon_pc_dir = $this->sys_path . 'pc/addons/' . $this->addon_key . DIRECTORY_SEPARATOR;
        $addon_server_dir = $this->addon_path . $this->addon_key . DIRECTORY_SEPARATOR;
        $addon_resource_dir = $this->root_path . 'public/addons/' . $this->addon_key . DIRECTORY_SEPARATOR;

        // 卸载管理端
        if (is_dir($addon_admin_dir)) File::del_dir($addon_admin_dir);
        // 卸载手机端
        if (is_dir($addon_app_dir)) File::del_dir($addon_app_dir);
        // 卸载电脑端
        if (is_dir($addon_pc_dir)) File::del_dir($addon_pc_dir);
        // 卸载管理端
        if (is_dir($addon_server_dir)) File::del_dir($addon_server_dir);
        // 卸载资源文件
        if (is_dir($addon_resource_dir)) File::del_dir($addon_resource_dir);

        return true;
    }

    /**
     * 安装依赖
     * @param $params
     * @return true
     * @throws Exception
     */
    protected function uninstallDepend($params = [])
    {
        $Depend = (new Depend);

        // 获取冲突保留的依赖设置
        $uninstall_reserve_depend_list = $params['uninstall_reserve_depend_list'] ?? request()->param('uninstall_reserve_depend_list');

        // composer 依赖删除
        $sys_composer_content = $Depend->getSysComposerContent();
        $addon_composer_content = $Depend->getAddonComposerContent($this->addon_key);

        if($addon_composer_content) {
            if (isset($addon_composer_content['require'])) {
                foreach ($sys_composer_content['require'] as $key => $item) {
                    if($Depend->checkAddonDelDepend(
                        $key,
                        $addon_composer_content['require'],
                        $uninstall_reserve_depend_list['server_composer']['require'] ?? []
                    )) {
                        unset($sys_composer_content['require'][$key]);
                    }
                }
            }
            if (isset($addon_composer_content['require-dev'])) {
                foreach ($sys_composer_content['require-dev'] as $key => $item) {
                    if($Depend->checkAddonDelDepend(
                        $key,
                        $addon_composer_content['require-dev'],
                        $uninstall_reserve_depend_list['server_composer']['require-dev'] ?? []
                    )) {
                        unset($sys_composer_content['require-dev'][$key]);
                    }
                }
            }

            $Depend->setSysComposerContent($sys_composer_content);
        }

        foreach (['admin', 'uniapp', 'pc'] as $item) {
            // npm 依赖删除
            $sys_npm_content = $Depend->getSysNpmContent($item);
            $addon_npm_content = $Depend->getAddonNpmContent($this->addon_key, $item);
            if($addon_npm_content) {
                if (isset($addon_npm_content['dependencies'])) {
                    foreach ($sys_npm_content['dependencies'] as $key => $tm) {
                        if($Depend->checkAddonDelDepend(
                            $key,
                            $addon_npm_content['dependencies'],
                            $uninstall_reserve_depend_list[$item.'_npm']['dependencies'] ?? []
                        )) {
                            unset($sys_npm_content['dependencies'][$key]);
                        }
                    }
                }
                if (isset($addon_npm_content['devDependencies'])) {
                    foreach ($sys_npm_content['devDependencies'] as $key => $tm) {
                        if($Depend->checkAddonDelDepend(
                            $key,
                            $addon_npm_content['devDependencies'],
                            $uninstall_reserve_depend_list[$item.'_npm']['devDependencies'] ?? []
                        )) {
                            unset($sys_npm_content['devDependencies'][$key]);
                        }
                    }
                }
                $Depend->setSysNpmContent($sys_npm_content, $item);
            }
        }

        // pages.json 删除
        $sys_page_content = $Depend->getSysPageContent();
        $addon_page_content = $Depend->getAddonPageContent($this->addon_key);

        if($addon_page_content) {
            if (isset($addon_page_content['pages'])) {
                foreach ($addon_page_content['pages'] as $key => $addon_item) {
                    foreach ($sys_page_content['pages'] as $k => $sys_item) {
                        // 寻找相同的插件路径
                        if(isset($addon_item['path']) && isset($sys_item['addon']) && $sys_item['path'] == $addon_item['path'] && $sys_item['addon'] == $this->addon_key) {
                            array_splice($sys_page_content['pages'], $k, 1);
                        }
                    }
                }
                $Depend->setSysPageContent($sys_page_content);
            }
        }

        return true;
    }

    /**
     * 安装sql
     * @return true
     * @throws Exception
     */
    protected function executeSql()
    {
        (new Sql)->executeSql($this->download_path . $this->addon_key . '/server/sql/uninstall.sql');
        return true;
    }

    /**
     * 删除插件配置信息
     * @return true
     */
    protected function delAddonInfo() {
        // 删除插件配置信息
        (new ModelService)->delAddonInfo($this->addon_key);
        UtilService::refreshInstallAddons();
        return true;
    }

    /**
     * 删除下载目录
     * @return true
     */
    protected function delDownloadDir() {
        File::del_dir($this->root_path . 'data/download/addons' . DIRECTORY_SEPARATOR . $this->addon_key . DIRECTORY_SEPARATOR);
        return true;
    }

    /**
     * 卸载菜单
     * @return true
     * @throws DbException
     */
    public function delMenus()
    {
        if($this->addon_key && Db::name('system_menu')->where('addon', $this->addon_key)->count()) {
            Db::name('system_menu')->where('addon', $this->addon_key)->delete();
        }
        return true;
    }

    /**
     * 删除计划任务
     * @return true
     * @throws DbException
     */
    public function delCrontab()
    {
        if($this->addon_key && Db::name('sys_crontab')->where('addon', $this->addon_key)->count()) {
            Db::name('sys_crontab')->where('addon', $this->addon_key)->delete();
        }
        return true;
    }

    /**
     * 执行插件卸载方法
     * @return true
     * @throws Exception
     */
    public function uninstallExecute()
    {
        // 获取方法
        $class = 'addons\\' . $this->addon_key . '\\' . 'Addon';
        if(!class_exists($class)) throw new Exception('插件类加载失败' . $class);

        $addonClass = (new $class());

        // 执行uninstall方法
        $addonClass->uninstall();

        // 清理缓存
        $addonClass->clear();

        return true;
    }

    /**
     * 卸载插件
     * @param array $params
     * @return true
     * @throws AddonsException
     */
    public function main($params = [])
    {
        try {
            // 卸载前检验
            $this->check();

            set_time_limit(0);

            // 执行卸载方法
            $this->uninstallExecute();

            // 执行卸载sql
            $this->executeSql();

            // 卸载插件目录
            $this->uninstallDir();

            // 卸载依赖
            $this->uninstallDepend($params);

            // 卸载菜单
            $this->delMenus();

            // 卸载计划任务
            $this->delCrontab();

            // 删除插件配置信息
            $this->delAddonInfo();

            // 清空下载目录
            $this->delDownloadDir();

            return true;

        } catch (\Exception $e) {
            throw new AddonsException($e->getMessage());
        }
    }
}